
<template>
  <!-- 自定义树形穿梭框组件、理论上左右均可选择是否为树形结构，目前固定为左侧树形、右侧无层级结构 -->
  <div class="tree-transfer">
    <!-- 穿梭框左侧 -->
    <div class="tree-transfer-left transfer-box">
      <div class="search-box">
        <el-input v-model="filterText" placeholder="输入关键字进行过滤" size="small" />
        <div class="checkAllBox">
          <el-checkbox
            v-model="allChecked"
            :indeterminate="isIndeterminate"
            @change="handleCheckAllChange"
          >全选</el-checkbox>
        </div>
      </div>
      <!-- 左侧采用element-ui的el-tree -->
      <div class="treeLeft-box">
        <el-tree
          ref="treeLeft"
          :expand-on-click-node="false"
          :check-on-click-node="false"
          :check-strictly="false"
          :filter-node-method="filterNode"
          :data="dataLeft"
          show-checkbox
          node-key="id"
          :default-expand-all="false"
          :props="defaultProps"
          @check-change="hanldeCheckChange"
        />
      </div>
    </div>
    <!-- 穿梭框中间按钮区域 -->
    <!-- <div class="tree-transfer-middle">
      <el-button icon="el-icon-arrow-right" size="small" @click="add" />
      <el-button icon="el-icon-arrow-left" size="small" style="margin-left: 0;margin-top: 10px;" @click="deleteNode" />
    </div> -->
    <!-- 穿梭框右侧 -->
    <div class="tree-transfer-right transfer-box">
      <div class="already-select">
        已选
      </div>
      <div class="checkAllBox" style="padding: 0 12px;">
        <!-- <el-checkbox
          v-model="allCheckedRight"
          :indeterminate="isIndeterminateRight"
          @change="handleCheckAllChangeRight"
        >全选</el-checkbox> -->
      </div>
      <!-- 右侧直接放置结果 -->
      <!-- 这里也采用tree结构，默认是对数据进行处理使得没有树形结构，也可以选择有树形结构 -->
      <!-- @check-change="rightChange" -->
      <div v-if="!spanShow || dataRight.length > 0" class="treeRight-box">
        <el-tree
          ref="treeRight"
          :expand-on-click-node="false"
          :check-on-click-node="false"
          :check-strictly="false"
          :data="dataRight"
          show-checkbox
          :default-expand-all="false"
          node-key="id"
          :props="defaultProps"
          :default-expanded-keys="expandedKeys"
          @check-change="hanldeCheckChangeRight"
          @node-expand="nodeExpand"
          @node-collapse="nodeCollapse"
        >
          <span slot-scope="{ node, data }" class="treeSpan">{{ data.name }}
            <i class="el-icon-close el-icon--right" @click="removeRightData(node, data)" />
          </span></el-tree>
      </div>
      <div v-else style="padding: 12px;font-size: 14px;">同上级管理员组</div>
    </div>
  </div>
</template>

<script>
/* eslint-disable no-cond-assign */
import applyApi from '@/framework/api/addApply'

export default {
  props: {
    spanShow: {
      type: Boolean,
      default: () => {
        return true
      }
    },
    // 接口所需参数
    columnProps: {
      type: Object,
      default: () => {
        return {
          groupId: '', // 当前被授权的管理员组的组ID
          relType: 0 // 0-可授权范围，1-管理范围
        }
      }
    },
    // 接口对象
    api: {
      type: Object,
      default: () => {
        return applyApi
      }
    },
    value: {
      type: String,
      default: ''
    },
    selectData: {
      type: Array,
      default: () => {
        return []
      }
    },
    defaultProps: {
      type: Object,
      default: () => {
        return {
          children: 'children',
          label: 'label'
        }
      }
    }
  },
  data() {
    return {
      expandedKeys: [],
      allChecked: false,
      allCheckedRight: false,
      isIndeterminate: false,
      isIndeterminateRight: false,
      filterText: '',
      yuansiData: [],
      dataLeft: [],
      dataRight: [],
      ids: [],
      nodes: []
    }
  },
  watch: {
    value: {
      handler(newVal, oldVal) {

      }
    },
    filterText(val) {
      this.$refs.treeLeft.filter(val)
    }
  },
  created() {
    this.handleInit()
  },
  methods: {
    handleInit() {
      this.getList().then((res) => {
        this.setData()
      })
    },
    setData() {
      if (this.selectData && this.selectData.length) {
        this.dataRight = this.selectData
        const stack = [...this.dataRight]
        let node
        while ((node = stack.shift()) !== undefined) {
          if (this.$refs.treeLeft.getNode(node).checked === false && !node.children.length) {
            this.$refs.treeLeft.setChecked(node.id, true, true)
          }
          // 如果有子元素的话进行压栈操作
          if (node.children) stack.unshift(...node.children)
        }
      }
    },
    hanldeCheckChange(item) {
      let flag = true
      const stack = [...this.dataLeft]
      let node = {}
      while ((node = stack.shift()) !== undefined) {
        if (this.$refs.treeLeft.getNode(node).checked === false) {
          // this.$refs.treeRight.setChecked(node.id, true, true)
          flag = false
        }
        // 如果有子元素的话进行压栈操作
        if (node.children) stack.unshift(...node.children)
      }

      if (flag) {
        this.allChecked = true
      } else {
        this.allChecked = false
      }
      this.add()
    },
    hanldeCheckChangeRight(item) {
      let flag = true
      const stack = [...this.dataRight]
      let node
      while ((node = stack.shift()) !== undefined) {
        if (this.$refs.treeRight.getNode(node).checked === false) {
          // this.$refs.treeRight.setChecked(node.id, true, true)
          flag = false
        }
        // 如果有子元素的话进行压栈操作
        if (node.children) stack.unshift(...node.children)
      }

      if (flag) {
        this.allCheckedRight = true
      } else {
        this.allCheckedRight = false
      }
    },
    getList() {
      return new Promise((resolve, reject) => {
        this.api.getParentGroupFunction(this.columnProps).then((res) => {
          this.dataLeft = res.data
          resolve('数据请求完成')
        })
      })
    },
    handleCheckAllChange() { // 全选按钮勾上的方法事件
      this.isIndeterminate = false // 设置全选按钮样式不为半选
      if (this.allChecked === true) { // 如果是当前值是全选，依次遍历节点设置勾选，同时过滤的disabled为true的
        // 深度遍历
        const stack = [...this.dataLeft]
        let node
        while ((node = stack.shift()) !== undefined) {
          if (this.$refs.treeLeft.getNode(node).checked === false) {
            this.$refs.treeLeft.setChecked(node.id, true, true)
          }
          // 如果有子元素的话进行压栈操作
          if (node.children) stack.unshift(...node.children)
        }
      } else { // 当前值不是全选，设置勾选列表为空
        this.$refs.treeLeft.setCheckedKeys([])
      }
    },
    handleCheckAllChangeRight() { // 全选按钮勾上的方法事件
      this.isIndeterminateRight = false // 设置全选按钮样式不为半选
      if (this.allCheckedRight === true) { // 如果是当前值是全选，依次遍历节点设置勾选，同时过滤的disabled为true的
        // 深度遍历
        const stack = [...this.dataRight]
        let node
        while ((node = stack.shift()) !== undefined) {
          if (this.$refs.treeRight.getNode(node).checked === false) {
            this.$refs.treeRight.setChecked(node.id, true, true)
          }
          // 如果有子元素的话进行压栈操作
          if (node.children) stack.unshift(...node.children)
        }
      } else { // 当前值不是全选，设置勾选列表为空
        this.$refs.treeRight.setCheckedKeys([])
      }
    },
    filterNode(value, data) {
      if (!value) return true
      return data.name.indexOf(value) !== -1
    },
    add() {
      const _that = this
      const getC = this.$refs.treeLeft.getCheckedNodes()
      const getHC = this.$refs.treeLeft.getHalfCheckedNodes()
      const selected_nodes = getHC.concat(getC)
      const selected_ids = new Set() // 记录选中的节点tree_id
      const used_ids = new Set() // 记录已经查询过的节点
      // 遍历初始化selected_ids
      for (const node of selected_nodes) {
        selected_ids.add(node.id)
      }
      this.$emit('input', Array.from(selected_ids).join(','))
      this.$emit('getChecked', selected_nodes, 'change')

      // 最终的结果数据用一个根节点存储, 为了对齐递归的数据结构
      const root_node = {
        id: -1,
        children: []
      }
      // 添加给parent_node节点一个新节点 node
      // 注意:node 的类型是原始的 tree 节点
      // 而parent_node 的类型是真正的结果节点
      function AddNode(node, parent_node) {
        if (
          !selected_ids.has(node.id) ||
          used_ids.has(node.id)
        ) {
          return
        }
        used_ids.add(node.id) // 加过的要存入 used_ids 做标记
        const key = _that.defaultProps.label
        const real_node = {
          id: node.id,
          children: [],
          // key: node[key],
          desc: node.desc,
          grade: node.grade
          // 存储一下节点的数据
        }
        real_node[key] = node[key]
        // // 添加子节点
        if (node.children) {
          for (const child_node of node.children) {
            AddNode(child_node, real_node)
          }
        }
        if (real_node.children.length === 0) {
          delete real_node.children
        }
        if (!real_node.grade) {
          delete real_node.grade
        }
        if (!real_node.desc) {
          delete real_node.desc
        }
        parent_node.children.push(real_node)
      }
      for (const node of selected_nodes) {
        AddNode(node, root_node)
      }
      const result = root_node.children
      // result[0].label = "已选组织"

      if (result && result.length) {
        this.dataRight = result
      } else {
        this.dataRight = []
      }
    },
    // 点击按钮删除
    deleteNode() {
      const {
        remove
      } = this.$refs.treeRight

      const dataArr = this.$refs.treeRight.getCheckedNodes()
      const dataArr1 = this.$refs.treeRight.getHalfCheckedNodes()
      const selected_nodes = dataArr.concat(dataArr1)

      const dataArrLeft = this.$refs.treeLeft.getCheckedNodes()

      const selected_ids = new Set() // 记录选中的节点tree_id
      const selected_left_ids = new Set() // 记录已经查询过的节点
      // 遍历初始化selected_ids
      for (const node of selected_nodes) {
        selected_ids.add(node.id)
      }
      for (const node of dataArrLeft) {
        selected_left_ids.add(node.id)
      }
      const keys = Array.from(new Set([...selected_left_ids].filter((x) => !selected_ids.has(x))))
      // const aa = [...selected_left_ids]
      // for (const i of selected_nodes) {
      //   const index = [...selected_left_ids].findIndex(d => d === i.id)
      //   aa.splice(index, 1)
      // }
      // this.$refs.treeLeft.setCheckedKeys([])
      // this.$refs.treeLeft.setCheckedKeys(aa)
      this.$refs.treeLeft.setCheckedKeys(keys)

      dataArr.forEach((item) => {
        remove(item)
      })

      // 全选按钮
      if (this.dataRight.length === 0) {
        this.allCheckedRight = false
      }

      // 抛出数据
      this.giveNodes()
    },
    // 抛出数据
    giveNodes() {
      const getC = this.$refs.treeLeft.getCheckedNodes()
      const getHC = this.$refs.treeLeft.getHalfCheckedNodes()
      const selected_nodes = getHC.concat(getC)
      const selected_ids = new Set() // 记录选中的节点tree_id
      // 遍历初始化selected_ids
      for (const node of selected_nodes) {
        selected_ids.add(node.id)
      }

      this.$emit('input', Array.from(selected_ids).join(','))
      this.$emit('getChecked', selected_nodes, 'change')
    },
    removeRightData(node, data) {
      this.$refs.treeRight.setCheckedNodes([data])
      this.deleteNode()
    },
    nodeExpand(obj, ndoe, self) {
      this.expandedKeys.push(obj.id)
    },
    nodeCollapse(obj, ndoe, self) {
      this.expandedKeys = this.expandedKeys.filter((item) => {
        return item !== obj.id
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.tree-transfer {
  display: flex;
  margin-top: 10px;

  .tree-transfer-middle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 80px;
  }

  .transfer-box {
    height: 408px;
    flex: 1;
    background-color: white;
    border-radius: 4px;
    border: 1px solid #DCDFE6;
    overflow: hidden;
  }

  .checkAllBox {
    margin: 10px 0;
  }

  .tree-transfer-right {
    padding: 0;

    .already-select {
      padding: 12px;
      padding-bottom: 10px;
      border-bottom: solid 1px #D8D8D8;
      font-size: 14px;
    }
  }

  .tree-transfer-left {
    box-sizing: border-box;

    .search-box {
      padding: 12px;
      padding-bottom: 0;
    }
  }

  .treeLeft-box {
    height: 302px;
    overflow: auto;
    padding: 0 12px;
  }

  .treeRight-box {
    height: 302px;
    overflow: auto;
    padding: 0 12px;

    ::v-deep .el-checkbox {
      opacity: 0;
    }

    ::v-deep .el-checkbox__inner {
      max-width: 0px;
    }
    .treeSpan{
      width: 100%;
      i{
        float: right;
        margin-right: 5px;
      }
    }
  }
}
</style>
